package com.cz.video.website.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cz.video.common.constant.CacheNames;
import com.cz.video.common.constant.HistoryConstants;
import com.cz.video.common.core.domain.PageQuery;
import com.cz.video.common.core.page.TableDataInfo;
import com.cz.video.common.helper.LoginHelper;
import com.cz.video.common.utils.DateUtils;
import com.cz.video.common.utils.MapstructUtils;
import com.cz.video.common.utils.StringUtils;
import com.cz.video.common.utils.redis.RedisUtils;
import com.cz.video.website.domain.WebsiteHistory;
import com.cz.video.website.domain.bo.WebsiteHistoryBo;
import com.cz.video.website.domain.vo.WebsiteHistoryVo;
import com.cz.video.website.mapper.WebsiteHistoryMapper;
import com.cz.video.website.service.WebsiteHistoryService;
import lombok.AllArgsConstructor;
import org.redisson.api.*;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 点赞 服务实现类
 * </p>
 *
 */
@Service
@AllArgsConstructor
public class WebsiteHistoryServiceImpl implements WebsiteHistoryService {
  private final WebsiteHistoryMapper historyMapper;

  @Override
  public TableDataInfo<WebsiteHistoryVo> page(WebsiteHistoryBo history, PageQuery pageQuery) {
    Page<WebsiteHistoryVo> page = historyMapper.selectPageList(pageQuery.build(), this.buildQueryWrapper(history));
    return TableDataInfo.build(page);
  }

  @Override
  public List<WebsiteHistoryVo> list(WebsiteHistoryBo historyBo) {
    return historyMapper.selectWebsiteHistoryList(this.buildQueryWrapper(historyBo));
  }

  @Override
  public WebsiteHistoryVo get(Long id) {
    return historyMapper.selectVoById(id);
  }


  @Override
  public int add(WebsiteHistoryBo history) {
    return historyMapper.insert(history);
  }

  @Override
  public int update(WebsiteHistoryBo history) {
    return historyMapper.updateById(history);
  }

  @Override
  public int deleteByIds(Long[] ids) {
    return historyMapper.delete(Wrappers.<WebsiteHistory>lambdaQuery()
        .eq(WebsiteHistory::getUserId, LoginHelper.getUserId())
        .in(WebsiteHistory::getVideoId, (Object[]) ids));
  }

    @Override
    public boolean addOrUpdate(WebsiteHistoryBo historyBo) {
      return historyMapper.insertOrUpdateTime(historyBo);
    }

    @Override
    public boolean reflush(Long clientUserId) {
        if (clientUserId==null)
            return false;
        String key = CacheNames.CLIENT_HISTORY.split("#")[0] + ":" + LoginHelper.getUserId();
        Map<String, WebsiteHistory> cacheMap = RedisUtils.getCacheMap(key);
        boolean flag=false;
        if (CollUtil.isNotEmpty(cacheMap.values())){
            ArrayList<WebsiteHistory> histories = CollUtil.newArrayList(cacheMap.values());
            for (Object websiteHistoryBo : histories) {
                WebsiteHistoryBo historyBo = (WebsiteHistoryBo) websiteHistoryBo;
                historyBo.setId(IdUtil.getSnowflake().nextId()).setUserId(clientUserId);
                if (historyBo.getCurrentTime()==null)
                    historyBo.setCurrentTime(0);
            }
            flag= historyMapper.insertOrUpdateTimeBatch(histories);
        }
        if (flag){
            RedisUtils.deleteObject(key);
        }
        return flag;
    }

    @Override
    public boolean reflushBatch(List<Long> userIdList) {
        //1.批量读取这些用户的历史记录
        RedissonClient redissonWebsite = RedisUtils.getClient();
        BatchOptions options = BatchOptions.defaults().executionMode(BatchOptions.ExecutionMode.IN_MEMORY);
        RBatch batch = redissonWebsite.createBatch(options);
        List<String> keyList=new ArrayList();
        for (Long userId : userIdList) {
            String key = StringUtils.substringBeforeLast(CacheNames.CLIENT_HISTORY, "#") + ":" + userId;
            keyList.add(key);
            RMapAsync<Object, Object> map = batch.getMap(key); // 通过键获取映射对象
            map.readAllValuesAsync(); // 添加异步读取映射所有值的操作
        }
        BatchResult<?> batchResult = batch.execute(); // 执行所有操作
        //2.立马删除这些key,减少在删除之前，这些历史记录又增加了，减少丢失数据的几率
        RedisUtils.deleteKeyBatch(keyList);
        //3.转换为list
        List<List<WebsiteHistoryBo>> results = (List<List<WebsiteHistoryBo>>) batchResult.getResponses(); // 获取所有操作的结果
        List<WebsiteHistoryBo> cacheValueList = new ArrayList<>();
        for (var result : results) {
            CollUtil.addAll(cacheValueList,result);// 将所有映射的值添加到集合中去
        }
        //4.刷新到数据库里面
        if (CollUtil.isNotEmpty(cacheValueList)){
            return historyMapper.insertOrUpdateTimeBatch(MapstructUtils.convert(cacheValueList,WebsiteHistory.class));
        }
        return false;
    }

    @Override
    public boolean refreshAll() {
        String key = StringUtils.substringBeforeLast(CacheNames.CLIENT_HISTORY, "#");
        List<WebsiteHistoryBo> histroyList = RedisUtils.getCacheMapValueByPrefix(key);
        boolean updated=false;
        if (CollUtil.isNotEmpty(histroyList))
            updated= historyMapper.updateBatchById(MapstructUtils.convert(histroyList,WebsiteHistory.class));
        //删除缓存
        if (updated){
            RedisUtils.deleteByPrefix(key);
        }
        return updated;
    }

    @Override
    public boolean addCache(WebsiteHistoryBo historyBo) {
        if (!StpUtil.isLogin())
            return false;
         historyBo.setUserId(LoginHelper.getUserId()).setUpdateTime(new Date());
        String key = CacheNames.CLIENT_HISTORY.split("#")[0] + ":" + LoginHelper.getUserId();
        int size = RedisUtils.getClient().getMap(key).size();
        boolean flag=false;
        //超过阈值就刷新到数据库里面
        if (size> HistoryConstants.MAX_HISTORY_NUM){
            Map<String, WebsiteHistoryBo> cacheMap = RedisUtils.getCacheMap(key);
            ArrayList websiteHistoryBos = CollUtil.newArrayList(cacheMap.values());
            websiteHistoryBos.add(historyBo);
            for (Object websiteHistoryBo : websiteHistoryBos) {
                WebsiteHistoryBo tempHistory = (WebsiteHistoryBo) websiteHistoryBo;
                tempHistory.setId(IdUtil.getSnowflake().nextId()).setUserId(LoginHelper.getUserId());
                if (tempHistory.getCurrentTime()==null)
                    tempHistory.setCurrentTime(0);
            }
            flag=historyMapper.insertOrUpdateTimeBatch(websiteHistoryBos);
            if (flag){
                RedisUtils.deleteObject(key);
            }
        }else {
            //把当前的浏览历史放到缓存里
            RedisUtils.setCacheMapValue(key,String.valueOf(historyBo.getVideoId()),historyBo);
            historyBo.setId(IdUtil.getSnowflake().nextId());
            if (historyBo.getCurrentTime()==null)
                historyBo.setCurrentTime(0);
            historyMapper.insertOrUpdateTime(historyBo);
            flag=true;
        }
        return flag;
  }

    /**
   * 根据查询条件构建query wrapper
   *
   * @param history 查询条件
   *
   * @return query wrapper
   */
  private Wrapper<WebsiteHistory> buildQueryWrapper(WebsiteHistoryBo history) {
      Map<String, Object> params = history.getParams();
      QueryWrapper<WebsiteHistory> wrapper = Wrappers.query();
    wrapper
        .eq(ObjectUtil.isNotNull(history.getUserId()), "wh.user_id", history.getUserId())
        .eq(ObjectUtil.isNotNull(history.getVideoId()), "wh.video_id", history.getVideoId())
        .ge(ObjectUtil.isNotNull(params.get("beginTime")),"wh.create_time", DateUtils.parseDate(params.get("beginTime")) )
        .le(ObjectUtil.isNotNull(params.get("endTime")),"wh.create_time", DateUtils.parseDate(params.get("endTime")))
        .orderByDesc("wh.create_time")
      ;
      return wrapper;
  }
}
